home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / TCPUSER.C < prev    next >
C/C++ Source or Header  |  1989-09-03  |  7KB  |  344 lines

  1. /* User calls to TCP */
  2. #include "global.h"
  3. #include "timer.h"
  4. #include "mbuf.h"
  5. #include "netuser.h"
  6. #include "internet.h"
  7. #include "tcp.h"
  8.  
  9. int16 tcp_window = DEF_WND;
  10.  
  11. struct tcb *
  12. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  13. struct socket *lsocket;    /* Local socket */
  14. struct socket *fsocket;    /* Remote socket */
  15. int mode;        /* Active/passive/server */
  16. int16 window;        /* Receive window (and send buffer) sizes */
  17. void (*r_upcall)();    /* Function to call when data arrives */
  18. void (*t_upcall)();    /* Function to call when ok to send more data */
  19. void (*s_upcall)();    /* Function to call when connection state changes */
  20. char tos;
  21. char *user;        /* User linkage area */
  22. {
  23.     struct connection conn;
  24.     register struct tcb *tcb;
  25.     void send_syn();
  26.  
  27.     if(lsocket == NULLSOCK){
  28.         net_error = INVALID;
  29.         return NULLTCB;
  30.     }
  31.     conn.local.address = lsocket->address;
  32.     conn.local.port = lsocket->port;
  33.     if(fsocket != NULLSOCK){
  34.         conn.remote.address = fsocket->address;
  35.         conn.remote.port = fsocket->port;
  36.     } else {
  37.         conn.remote.address = 0;
  38.         conn.remote.port = 0;
  39.     }
  40.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  41.         if((tcb = create_tcb(&conn)) == NULLTCB){
  42.             net_error = NO_SPACE;
  43.             return NULLTCB;
  44.         }
  45.     } else if(tcb->state != LISTEN){
  46.         net_error = CON_EXISTS;
  47.         return NULLTCB;
  48.     }
  49.     tcb->user = user;
  50.     if(window != 0)
  51.         tcb->window = tcb->rcv.wnd = window;
  52.     else
  53.         tcb->window = tcb->rcv.wnd = tcp_window;
  54.     tcb->r_upcall = r_upcall;
  55.     tcb->t_upcall = t_upcall;
  56.     tcb->s_upcall = s_upcall;
  57.     tcb->tos = tos;
  58.     switch(mode){
  59.     case TCP_SERVER:
  60.         tcb->flags |= CLONE;
  61.     case TCP_PASSIVE:    /* Note fall-thru */
  62.         setstate(tcb,LISTEN);
  63.         break;
  64.     case TCP_ACTIVE:
  65.         /* Send SYN, go into SYN_SENT state */
  66.         tcb->flags |= ACTIVE;
  67.         send_syn(tcb);
  68.         setstate(tcb,SYN_SENT);
  69.         tcp_output(tcb);
  70.         tcp_stat.conout++;
  71.         break;
  72.     }
  73.     return tcb;
  74. }
  75. /* User send routine */
  76. int
  77. send_tcp(tcb,bp)
  78. register struct tcb *tcb;
  79. struct mbuf *bp;
  80. {
  81.     int16 cnt;
  82.     void send_syn();
  83.  
  84.     if(tcb == NULLTCB || bp == NULLBUF){
  85.         free_p(bp);
  86.         net_error = INVALID;
  87.         return -1;
  88.     }
  89.     cnt = len_mbuf(bp);
  90. #ifdef    TIGHT
  91.     /* If this would overfill our send queue, reject it entirely */
  92.     if(tcb->sndcnt + cnt > tcb->window){
  93.         free_p(bp);
  94.         net_error = WOULDBLK;
  95.         return -1;
  96.     }
  97. #endif
  98.     switch(tcb->state){
  99.     case CLOSED:
  100.         free_p(bp);
  101.         net_error = NO_CONN;
  102.         return -1;
  103.     case LISTEN:    /* Change state from passive to active */
  104.         tcb->flags |= ACTIVE;
  105.         send_syn(tcb);
  106.         setstate(tcb,SYN_SENT);    /* Note fall-thru */
  107.     case SYN_SENT:
  108.     case SYN_RECEIVED:
  109.     case ESTABLISHED:
  110.     case CLOSE_WAIT:
  111.         append(&tcb->sndq,bp);
  112.         tcb->sndcnt += cnt;
  113.         tcp_output(tcb);
  114.         break;
  115.     case FINWAIT1:
  116.     case FINWAIT2:
  117.     case CLOSING:
  118.     case LAST_ACK:
  119.     case TIME_WAIT:
  120.         free_p(bp);
  121.         net_error = CON_CLOS;
  122.         return -1;
  123.     }
  124.     return cnt;
  125. }
  126. /* User receive routine */
  127. int
  128. recv_tcp(tcb,bp,cnt)
  129. register struct tcb *tcb;
  130. struct mbuf **bp;
  131. int16 cnt;
  132. {
  133.     if(tcb == NULLTCB || bp == (struct mbuf **)NULL){
  134.         net_error = INVALID;
  135.         return -1;
  136.     }
  137.     /* cnt == 0 means "I want it all" */
  138.     if(cnt == 0)
  139.         cnt = tcb->rcvcnt;
  140.     /* If there's something on the queue, just return it regardless
  141.      * of the state we're in.
  142.      */
  143.     if(tcb->rcvcnt != 0){
  144.         /* See if the user can take all of it */
  145.         if(tcb->rcvcnt <= cnt){
  146.             cnt = tcb->rcvcnt;
  147.             *bp = tcb->rcvq;
  148.             tcb->rcvq = NULLBUF;
  149.         } else {
  150.             if((*bp = alloc_mbuf(cnt)) == NULLBUF){
  151.                 net_error = NO_SPACE;
  152.                 return -1;
  153.             }
  154.             pullup(&tcb->rcvq,(*bp)->data,cnt);
  155.             (*bp)->cnt = cnt;
  156.         }
  157.         tcb->rcvcnt -= cnt;
  158.         tcb->rcv.wnd += cnt;
  159.         /* Do a window update if it was closed */
  160.         if(cnt == tcb->rcv.wnd){
  161.             tcb->flags |= FORCE;
  162.             tcp_output(tcb);
  163.         }
  164.         return cnt;
  165.     } else {
  166.         /* If there's nothing on the queue, our action depends on what state
  167.          * we're in (i.e., whether or not we're expecting any more data).
  168.          * If no more data is expected, then simply return 0; this is
  169.          * interpreted as "end of file".
  170.          */
  171.         switch(tcb->state){
  172.         case LISTEN:
  173.         case SYN_SENT:
  174.         case SYN_RECEIVED:
  175.         case ESTABLISHED:
  176.         case FINWAIT1:
  177.         case FINWAIT2:
  178.             *bp = NULLBUF;
  179.             net_error = WOULDBLK;
  180.             return -1;
  181.         case CLOSED:
  182.         case CLOSE_WAIT:
  183.         case CLOSING:
  184.         case LAST_ACK:
  185.         case TIME_WAIT:
  186.             *bp = NULLBUF;
  187.             return 0;
  188.         }
  189.     }
  190.     return 0;    /* Not reached, but lint doesn't know that */
  191. }
  192. /* This really means "I have no more data to send". It only closes the
  193.  * connection in one direction, and we can continue to receive data
  194.  * indefinitely.
  195.  */
  196. int
  197. close_tcp(tcb)
  198. register struct tcb *tcb;
  199. {
  200.     if(tcb == NULLTCB){
  201.         net_error = INVALID;
  202.         return -1;
  203.     }
  204.     switch(tcb->state){
  205.     case LISTEN:
  206.     case SYN_SENT:
  207.         close_self(tcb,NORMAL);
  208.         return 0;
  209.     case SYN_RECEIVED:
  210.     case ESTABLISHED:
  211.         tcb->sndcnt++;
  212.         tcb->snd.nxt++;
  213.         setstate(tcb,FINWAIT1);
  214.         tcp_output(tcb);
  215.         return 0;
  216.     case CLOSE_WAIT:
  217.         tcb->sndcnt++;
  218.         tcb->snd.nxt++;
  219.         setstate(tcb,LAST_ACK);
  220.         tcp_output(tcb);
  221.         return 0;
  222.     case FINWAIT1:
  223.     case FINWAIT2:
  224.     case CLOSING:
  225.     case LAST_ACK:
  226.     case TIME_WAIT:
  227.         net_error = CON_CLOS;
  228.         return -1;
  229.     }
  230.     return -1;    /* "Can't happen" */
  231. }
  232. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  233.  * not in the CLOSED state. This function should normally be called by the
  234.  * user only in response to a state change upcall to CLOSED state.
  235.  */
  236. int
  237. del_tcp(tcb)
  238. register struct tcb *tcb;
  239. {
  240.     void unlink_tcb();
  241.     struct reseq *rp,*rp1;
  242.  
  243.     if(tcb == NULLTCB){
  244.         net_error = INVALID;
  245.         return -1;
  246.     }
  247.     unlink_tcb(tcb);
  248.     stop_timer(&tcb->timer);
  249.     stop_timer(&tcb->timeout);
  250.     stop_timer(&tcb->rtt_timer);
  251.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  252.         rp1 = rp->next;
  253.         free_p(rp->bp);
  254.         free((char *)rp);
  255.     }
  256.     tcb->reseq = NULLRESEQ;
  257.     free_p(tcb->rcvq);
  258.     free_p(tcb->sndq);
  259.     free((char *)tcb);
  260.     return 0;
  261. }
  262. /* Do printf on a tcp connection */
  263. /*VARARGS2*/
  264. tprintf(tcb,message,arg1,arg2,arg3)
  265. struct tcb *tcb;
  266. char *message,*arg1,*arg2,*arg3;
  267. {
  268.     struct mbuf *bp;
  269.     int len;
  270.  
  271.     if(tcb == NULLTCB)
  272.         return 0;
  273.  
  274.     if ((bp = alloc_mbuf(160)) == NULLBUF)
  275.         return 0;
  276.  
  277.     len = sprintf(bp->data,message,arg1,arg2,arg3);
  278.     bp->cnt = strlen(bp->data);
  279.     send_tcp(tcb,bp);
  280.     return len;
  281. }
  282. /* Return 1 if arg is a valid TCB, 0 otherwise */
  283. int
  284. tcpval(tcb)
  285. struct tcb *tcb;
  286. {
  287.     register int i;
  288.     register struct tcb *tcb1;
  289.  
  290.     if(tcb == NULLTCB)
  291.         return 0;    /* Null pointer can't be valid */
  292.     for(i=0;i<NTCB;i++){
  293.         for(tcb1=tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next){
  294.             if(tcb1 == tcb)
  295.                 return 1;
  296.         }
  297.     }
  298.     return 0;
  299. }
  300. kick_tcp(tcb)
  301. register struct tcb *tcb;
  302. {
  303.     void tcp_timeout();
  304.  
  305.     if(!tcpval(tcb))
  306.         return -1;
  307.     tcp_timeout((char *)tcb);
  308.     return 0;
  309. }
  310. reset_tcp(tcb)
  311. register struct tcb *tcb;
  312. {
  313.     close_self(tcb,RESET);
  314. }
  315. /* Return character string corresponding to a TCP well-known port, or
  316.  * the decimal number if unknown.
  317.  */
  318. char *
  319. tcp_port(n)
  320. int16 n;
  321. {
  322.     static char buf[32];
  323.  
  324.     switch(n){
  325.     case ECHO_PORT:
  326.         return "echo";
  327.     case DISCARD_PORT:
  328.         return "discard";
  329.     case FTPD_PORT:
  330.         return "ftp_data";
  331.     case FTP_PORT:
  332.         return "ftp";    
  333.     case TELNET_PORT:
  334.         return "telnet";
  335.     case SMTP_PORT:
  336.         return "smtp";
  337.     case FINGER_PORT:
  338.         return "finger";
  339.     default:
  340.         sprintf(buf,"%u",n);
  341.         return buf;
  342.     }
  343. }
  344.